var DataContext = function () {
	var languageCode = 'en',
		EntitySet = function (dataService, mapToModel) {
			var items = [],
            
				toModelObj = function (data, results) {
					if (data === null)
						return;
					items = [];
					var json = data;
                    
                    console.log('EntitySet:\n' + ko.toJSON(json));
					if (json.response_code == undefined || json.response_code != 0) {
                        /* login case, I think must be changed, I want to all api have one format JSON result return */
                        if (json.access_token != undefined){
                            var item = mapToModel(json);
                            items.push(item);
                            
                            results(items);
                            return json;
                        }
						var errorItem = mapper.toError(json);
						items.push(errorItem);
						results(items);
						return errorItem;
					}
                    else{
                        var item = mapToModel(json);
						items.push(item);
                        
                        results(items);
                    }
					
					return json;
				},

                toModelFromCache = function (data, strKey) {
                    if (data == null){
                        /* some thing went wrong, maybe data from location has been deleted => set flag is null*/
                        localStore.save(strKey, null);
                    }
                    else{
                        /* parse data and push it to items (list))*/
                        var item = mapToModel($.parseJSON(data));
                        items.push(item);
                    }
                    
                },

				saveFile = function (data, callback, rawData) {
                    
					if (callback.key != undefined) {
                        
						if ((callback.key.length >= 8 && callback.key.substr(0, 8) != "saveFile") || callback.key.length < 8) {
							localStore.save(callback.key, rawData);
						} else {
							if (data.length > 0 || data != undefined) {
                                
                                localStore.saveFile(callback.key, ko.toJSON(data)); // json data
                                localStore.save(callback.key, '1');
                            }
						}
					}
				},

				find = function (getFunc, callback) {
					return $.when(getFunc)
						.done(function (data) {
                            console.log(this.url);
							var json = toModelObj(data, callback.results);
                              
							if (json != undefined && json.response_code != undefined && json.response_code == 0) {
								saveFile(json, callback, data);
							}
						})
						.fail(function (e) {
                              console.log('error: '+ ko.toJSON(e));
//							if (callback.key != undefined && localStore.get(callback.key) != null) {
//								toModelObj(localStore.get(callback.key), callback.results);
//							}
						}).always(function () {});
				},

				findInBackground = function (getFunc, callback) {
					$.when(getFunc)
						.done(function (data) {
                            console.log(this.url);
                            
							var json = data;
							if (json != undefined && json.response_code != undefined && json.response_code == 0) {
								saveFile(json, callback, data);
							}
                              }).fail(function () {console.log(ko.toJSON(this));}).always(function () {});
				},

				get = function (callback) {
					return find(dataService.getData(callback), callback);
				},

				getFromLocal = function () {
					return items;
				},

				clearItems = function () {
					items = [];
				},

				getById = function (id) {
					return _.filter(items, function (i) {
						return i.id == id;
					});
				},
                getDataCache = function (data, callback) {
                    setTimeout(function () {
                               clearItems();
                               toModelFromCache(data, callback.key);
                               callback.results(getFromLocal());
                               callback.callbackFunc();
                               }, 100);
                };

			return {
				get: get,
				getById: getById,
				getFromLocal: getFromLocal,
				toModelObj: toModelObj,
				toModelFromCache: toModelFromCache,
				dataService: dataService,
				find: find,
				findInBackground: findInBackground,
				clearItems: clearItems,
                getDataCache: getDataCache
			};
		},

		session = new EntitySet(loginService, mapper.user),
		numberFreeBook = new EntitySet(sessionService, mapper.numberFreeBook),
		category = new EntitySet(cateService, mapper.category),
		overview = new EntitySet(bookService, mapper.overview),
		overviewStartPage = new EntitySet(bookService, mapper.overview),
		startPage = new EntitySet(bookService, mapper.startPage),
		startPageSetting = new EntitySet(bookService, mapper.startPageSetting),
		startPageSettingPost = new EntitySet(bookService, mapper.status),
		search = new EntitySet(bookService, mapper.overview),
		active = new EntitySet(bookService, mapper.status),
		favoriteFolder = new EntitySet(favoriteService, mapper.favoriteFolder),
		editFavorite = new EntitySet(bookService, mapper.status),
		syncFavorite = new EntitySet(favoriteService, mapper.syncFavorite),
		buy = new EntitySet(bookService, mapper.buythebook),
		comments = new EntitySet(bookService, mapper.comments),
		annotations = new EntitySet(bookService, mapper.annotations),
		postComments = new EntitySet(bookService, mapper.status),
		postShareEmail = new EntitySet(bookService, mapper.status),
		book = new EntitySet(bookService, mapper.book),
		setting = new EntitySet(settingService, mapper.status),
		getSetting = new EntitySet(settingService, mapper.getSetting),
		about = new EntitySet(aboutService, mapper.about),
		login = new EntitySet(loginService, mapper.user),
        logout = new EntitySet(loginService, mapper.status),
		register = new EntitySet(loginService, mapper.status),
		favorite = new EntitySet(favoriteService, mapper.favorite);
    
    /* register */
    register.register = function (callback) {
		return register.find(loginService.register(callback), callback);
	},
    /* end register */
    logout.logout = function (callback) {
		return logout.find(loginService.logout(callback), callback);
	},
    
    /* get book detail */
	book.getDetail = function (callback) {
	    if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        book.findInBackground(bookService.getDetail(callback), callback);
	        localStore.getFile(callback.key, function (data) {
               book.getDataCache(data, callback);
	        });
	        return $.when()
				.done(function () { }).fail(function () { }).always(function () { });
	    }
	    return book.find(bookService.getDetail(callback), callback);
	},

    /* about */
    about.getAbout = function(callback){
        if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        about.findInBackground(aboutService.getData(callback), callback);
	        localStore.getFile(callback.key, function (data) {
                               about.getDataCache(data, callback);
                               });
	        return $.when()
            .fail(function () { }).always(function () { });
	    }
        return about.find(aboutService.getData(callback), callback);
    },
    /* menu category */
    category.getMenu = function(callback){
        if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        category.findInBackground(cateService.getData(callback), callback);
            
	        localStore.getFile(callback.key, function (data) {
                               category.getDataCache(data, callback);
                               });
	        return $.when()
            .fail(function () { }).always(function () { });
	    }
        return category.find(cateService.getData(callback), callback);
    },
    /* overview */
    
	overview.getByCategory = function (callback) {
	    if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        overview.findInBackground(bookService.getOverview(callback), callback);
	        localStore.getFile(callback.key, function (data) {
                               overview.getDataCache(data, callback);
                               });
	        return $.when()
            .done(function () { }).fail(function () { }).always(function () { });
	    }
	    return overview.find(bookService.getOverview(callback), callback);
	},
/* active book */
	active.activeBook = function (callback) {
		return active.find(bookService.activeBook(callback), callback);
	},

	buy.buyTheBook = function (callback) {
		return buy.find(bookService.buyTheBook(callback), callback);
	},
    /* comment */
    comments.getComments = function(callback){
        if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        comments.findInBackground(bookService.getComments(callback), callback);
            
	        localStore.getFile(callback.key, function (data) {
                               comments.getDataCache(data, callback);
                               });
	        return $.when()
            .fail(function () { }).always(function () { });
	    }
        return comments.find(bookService.getComments(callback), callback);
    },

    postComments.post = function (callback) {
		return postComments.find(bookService.postComments(callback), callback);
	},
    /* end comment */
    /* annotations */
    annotations.getAnnotations = function(callback){
        if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        annotations.findInBackground(bookService.getAnnotations(callback), callback);
            
	        localStore.getFile(callback.key, function (data) {
                               annotations.getDataCache(data, callback);
                               });
	        return $.when()
            .fail(function () { }).always(function () { });
	    }
		return annotations.find(bookService.getAnnotations(callback), callback);
	},
    /* end annotations */
    
	

	postShareEmail.post = function (callback) {
		return postShareEmail.find(bookService.postShareEmail(callback), callback);
	},
/* favoriite folder */
	favoriteFolder.getAll = function (callback) {
        if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        localStore.getFile(callback.key, function (data) {
                               favoriteFolder.getDataCache(data, callback);
                               
                               });
	        return $.when()
            .fail(function () { }).always(function () { });
	    }
        
		return favoriteFolder.find(favoriteService.getFavoriteFolders(callback), callback);
	},

    editFavorite.add = function (callback) {
		return editFavorite.find(bookService.addFavorite(callback), callback);
	},
    editFavorite.remove = function (callback) {
        return editFavorite.find(bookService.removeFavorite(callback), callback);
    },
    /* end favorite */
    
    
    /* setting */
    getSetting.getSetting = function(callback){
        if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
	        getSetting.findInBackground(settingService.getData(callback), callback);
	        localStore.getFile(callback.key, function (data) {
                               getSetting.getDataCache(data, callback);
                               });
	        return $.when()
            .fail(function () { }).always(function () { });
	    }
        return getSetting.find(settingService.getData(callback), callback);
    },
	setting.updateSetting = function (callback) {
		return setting.find(settingService.update(callback), callback);
	},
    /* end setting */
	overview.search = function (callback) {
		return search.find(bookService.getBy(callback), callback);
	},
	
/* newest for start page */
    overviewStartPage.getNewestStartPage = function (callback) {
		if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
			overviewStartPage.findInBackground(bookService.getStartPage(callback), callback);
			localStore.getFile(callback.key, function (data) {
                               overviewStartPage.getDataCache(data, callback);
                               });
			return $.when();
		}
		return overviewStartPage.find(bookService.getNewestStartPage(callback), callback);
	},
	
/* end newest for start page */

/* start page */
    
	startPage.getStartPage = function (callback) {
		if (localStore.get(callback.key) != null && (callback.isServer == undefined || callback.isServer == false)) {
			startPage.findInBackground(bookService.getStartPage(callback), callback);
			localStore.getFile(callback.key, function (data) {
				startPage.getDataCache(data, callback);
			});
			return $.when()
				.fail(function () {}).always(function () {});
		}
		return startPage.find(bookService.getStartPage(callback), callback);
	},
    startPageSetting.getStartPageSetting = function (callback) {
		return startPageSetting.find(bookService.getStartPageSetting(callback), callback);
	},
    startPageSettingPost.postStartPageSetting = function (callback) {
		return startPageSettingPost.find(bookService.postStartPageSetting(callback), callback);
	},
/* end start page */
    
	session.refreshToken = function (callback) {
		return session.find(loginService.refreshToken(callback), callback);
	};
	
	return {
		category: category,
		overview: overview,
		overviewStartPage: overviewStartPage,
		startPage: startPage,
		startPageSetting: startPageSetting,
		startPageSettingPost: startPageSettingPost,
		book: book,
		buy: buy,
		favorite: favorite,
		favoriteFolder: favoriteFolder,
        editFavorite: editFavorite,
		syncFavorite: syncFavorite,
		setting: setting,
		getSetting: getSetting,
		comments: comments,
		annotations: annotations,
		postComments: postComments,
		postShareEmail: postShareEmail,
		active: active,
		about: about,
		login: login,
        logout: logout,
		register: register,
		session: session,
		numberFreeBook: numberFreeBook
	};
}
